﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Xml;

namespace CPPEI.Coolzon.Launcher
{
    public delegate void UpdatingEventHandle(int totalStep, int curStep, string message);

    public delegate void FinishedEventHandle(int totalStep, int curStep, string message, bool isHaveUpdate);
    public class UpdatingThread
    {
        public Thread _thread;
       
        private Common.AppInfo _appInfo;
        private string _downlodFolderName;
        private string _xmlDownlodFileName;
        private StackPanel _stackPanel;
        private XmlNode _updateFileNodes;
        private string _backupDestFullName;
        private string _failureFileName;

        private bool _isUpdateFinished;
        /// <summary>
        /// 已下载更新包的路径
        /// </summary>
        private string _destPatchFileSavePath;


        /// <summary>
        /// 已下载更新包文件名
        /// </summary>
        private string _patchFileSaveFolderName;

        /// <summary>
        /// 要被更新的版本号
        /// </summary>
        private string _targetVersion;

        /// <summary>
        /// 更新中文件复制事件
        /// </summary>
        public event UpdatingEventHandle Updating;


        /// <summary>
        /// 更新完成的事件
        /// </summary>
        public event FinishedEventHandle UpdateFinish;

        /// <summary>
        /// 更新失败的事件
        /// </summary>
        public event UpdatingEventHandle UpdateFailure;

        /// <summary>
        /// 构造出一个更显线程，用于应用程序的更新
        /// </summary>
        /// <param name="appInfo">将要被更新应用程序的信息</param>
        public UpdatingThread(Common.AppInfo appInfo,string destPatchFileSavePath, string patchFileSaveFolderName, string targetVersion)
        {
            _appInfo = appInfo;
            _destPatchFileSavePath = destPatchFileSavePath;
            _patchFileSaveFolderName = patchFileSaveFolderName;
            _targetVersion = targetVersion;
        }

        /// <summary>
        /// 启动更新
        /// </summary>
        public void Start()
        {
            if (_thread == null)
            {
                //构造更新线程，执行Running方法
                _thread = new Thread(Running);
                //更新线程启动
                _thread.Start();
            }
        }

        public void Sleep(int sleepvalue)
        {
            Thread.Sleep(sleepvalue);
        }

        /// <summary>
        /// 执行更新操作
        /// 1.获取当前版本需要更新计划
        /// 2.根据更新计划，下载需要的更新包到当前程序的安装路径
        /// 3.复制已下载的更新包到程序的安装路径
        /// </summary>
        private void Running()
        {

            DecompressionPatchFile(_destPatchFileSavePath, _patchFileSaveFolderName,_targetVersion);
        }

        private string GetTargetVersion(string targetVersion)
        {
            if (string.IsNullOrEmpty(targetVersion))
            {
                return string.Empty;
            }
            string[] sign = targetVersion.Split('.');
            if (0 < sign.Length && sign.Length < 4)
            {
                if (sign.Length == 2)
                {
                    return targetVersion += ".0.0";
                }
                else if (sign.Length == 3)
                {
                    return targetVersion += ".0";
                }
            }
            return targetVersion;
        }

     

        /// <summary>
        /// 执行备份文件
        /// </summary>
        private void BackupFiles(XmlNode updateFileNodes)
        {
            if (updateFileNodes == null)
            {
                return;
            }

            //创建备份的文件夹Backup
            PathMap.CreateSubdirectory(_appInfo.Directory, "Backup");

             _backupDestFullName = PathMap.GetDownloadFilePath(_appInfo.Directory, "Backup", string.Empty);

            for (int i = 0; i < updateFileNodes.ChildNodes.Count; i++)
            {
                XmlNode c = updateFileNodes.ChildNodes[i];
                if (c.Attributes != null)
                {
                    //将要备份的文件路径
                    string backupFilePath = PathMap.GetTargetFilePath(_appInfo, c.Attributes["TargetPath"].Value);

                    //判断要更新的文件，是否存在程序文件中
                    if (File.Exists(backupFilePath))
                    {
                        FileInfo fileInfo = new FileInfo(backupFilePath);
                        if (File.Exists(_backupDestFullName + "\\" + fileInfo.Name))
                        {
                            fileInfo.IsReadOnly = false;
                            File.Delete(_backupDestFullName + "\\" + fileInfo.Name);
                        }
                        fileInfo.CopyTo(_backupDestFullName + "\\" + fileInfo.Name);
                    }
                }

            }
        }

        /// <summary>
        /// 执行复制文件
        /// </summary>
        /// <param name="schedule"></param>
        private void CopyFiles(ServiceReference.UpdateSchedule schedule)
        {


            //读取已下载的xml文件信息

            if (!string.IsNullOrEmpty(_downlodFolderName) && !string.IsNullOrEmpty(_xmlDownlodFileName))
            {
                string xmlFilePath = _appInfo.Directory + "Patches\\" + _appInfo.Product + "\\" + _appInfo.Type + "\\" + _downlodFolderName + "\\" + _xmlDownlodFileName;
                if (System.IO.File.Exists(xmlFilePath))
                {
                    XmlDocument xmlUpdateFile = new XmlDocument();
                    xmlUpdateFile.Load(xmlFilePath);

                    XmlNode updateFileNodes = xmlUpdateFile.SelectSingleNode("Patch");
                    _updateFileNodes = null;

                    if (updateFileNodes != null)
                    {
                        //执行备份
                        BackupFiles(updateFileNodes);
                        _updateFileNodes = updateFileNodes;


                        string fileName = string.Empty; ;
                        string targetPath = string.Empty;
                        string filePath = string.Empty;
                        int index = 0;
                        try
                        {
                            for (int i = 0; i < updateFileNodes.ChildNodes.Count; i++)
                            {
                                index = i;
                                XmlNode c = updateFileNodes.ChildNodes[i];
                                if (c.Attributes != null)
                                {
                                    fileName = c.Attributes["Name"].Value;
                                    targetPath = PathMap.GetTargetFilePath(_appInfo, c.Attributes["TargetPath"].Value);
                                    filePath = PathMap.GetFilePath(_appInfo, c.Attributes["Path"].Value, _downlodFolderName);
                                    string oFilePath = c.Attributes["Path"].Value;
                                    if (System.IO.File.Exists(filePath))
                                    {
                                        if (File.Exists(targetPath))
                                        {
                                            File.Delete(targetPath);
                                        }
                                        else
                                        {
                                            //递归创建文件夹
                                            char[] sepatator = { '\\' };

                                            string[] filePaths = oFilePath.Split(sepatator, StringSplitOptions.RemoveEmptyEntries);
                                            CreateParentFolders(_appInfo.Directory, filePaths);
                                        }
                                        FileInfo fileInfo = new FileInfo(filePath);

                                        //CopyFilesUpdating(updateFileNodes.ChildNodes.Count, i, string.Format("复制文件 : {0}", fileName));
                                        fileInfo.CopyTo(targetPath);
                                    }
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            Common.Logger.ErrorToTag("UpdatingProcess", "复制文件：{0}失败,targetPath:{1},ex:{2}",
                            fileName,
                            targetPath,
                            ex);
                            OnUpdatingFailure(schedule.Files.Length, index, string.Format("复制文件：{0}失败", fileName));
                            return;
                        }
                        finally
                        {
                            OnUpdatingFinished(schedule.Files.Length, schedule.Files.Length, "更新完毕", true);
                        }
                    }

                }

            }
        }

        /// <summary>
        /// 递归创建文件的父文件夹
        /// </summary>
        /// <param name="strdir"></param>
        private void CreateParentFolders(string strDir ,string[] filePaths)
        {
            
            if (filePaths != null && filePaths.Length > 0)
            {
                List<string> listfilePaths = filePaths.ToList();
                if (listfilePaths.Count > 3)
                {
                   
                        //创建父类文件夹
                        PathMap.CreateSubdirectory(strDir, listfilePaths[1]);
                        strDir = PathMap.GetDownloadFilePath(strDir, listfilePaths[1], string.Empty);
                        listfilePaths.RemoveAt(1);
                        CreateParentFolders(strDir, listfilePaths.ToArray());
                  
                }
                else if (listfilePaths.Count == 3)
                {
                    //创建父类文件夹
                    PathMap.CreateSubdirectory(strDir, filePaths[1]);
                }
            }
          
        }

        private void OnDownloadFilesUpdating(int totalStep, int currentStep, string message)
        {
            //if (DownloadFilesUpdating != null)
            //{
            //    DownloadFilesUpdating(totalStep, currentStep, message);
            //}
        }

        private void OnUpdating(int totalStep, int currentStep, string message)
        {
            if (Updating != null)
            {
                Updating(totalStep, currentStep, message);
            }
        }

        private void OnUpdatingFinished(int totalStep, int currentStep, string message, bool isHaveUpdate)
        {
            if (UpdateFinish != null)
            {
                if (isHaveUpdate)
                {
                    //更新客户端的版本号
                    OnUpdating(8, 6, "正在更新版本...");
                    _appInfo.Version = new Version(GetTargetVersion(_targetVersion));
                    Common.CoolzonRegistryUtil.SaveAppInfo(_appInfo.Company, _appInfo.Product, _appInfo);
                }
                //DeleteBackupAllFile(_backupDestFullName);
                UpdateFinish(totalStep, currentStep, message, isHaveUpdate);

            }
        }

        private void OnUpdatingFailure(int totalStep, int currentStep, string errorMessage)
        {
            if (UpdateFailure != null)
            {
                UpdateFailure(totalStep, currentStep, errorMessage);
                RollbackFiles(_updateFileNodes);
            }
        }


        /// <summary>
        /// 执行回滚文件
        /// </summary>
        private void RollbackFiles(XmlNode updateFileNodes)
        {
           
            if (updateFileNodes == null || string.IsNullOrEmpty(_backupDestFullName))
            {
                return;
            }
         
            int index = 0;
            //删除已经更新的文件
            Updating(8, 5, "正在执行回滚...");
            for (int i = 0; i < updateFileNodes.ChildNodes.Count; i++)
            {
                index = i;
                XmlNode c = updateFileNodes.ChildNodes[i];
                if (c.Attributes != null)
                {
                    string fileName = c.Attributes["Name"].Value;
                    string targetPath = PathMap.GetTargetFilePath(_appInfo, c.Attributes["TargetPath"].Value);
                   // string filePath = PathMap.GetFilePath(_appInfo, c.Attributes["Path"].Value, _downlodFolderName);
                    if (_failureFileName != fileName)
                    {
                        if (File.Exists(targetPath))
                        {
                            File.Delete(targetPath);
                        }
                    }
                }
            }


            for (int j = 0; j < updateFileNodes.ChildNodes.Count; j++)
            {
                 XmlNode c = updateFileNodes.ChildNodes[j];
                 if (c.Attributes != null)
                 {
                     //备份的文件路径
                     string destFullName = PathMap.GetDownloadFilePath(_appInfo.Directory, "Backup", string.Empty);
                     string fileName = c.Attributes["Name"].Value;
                     destFullName = destFullName + "\\" + fileName;
                     if (_failureFileName != fileName)
                     {
                         if (File.Exists(destFullName))
                         {
                             string targetPath = PathMap.GetTargetFilePath(_appInfo, c.Attributes["TargetPath"].Value);
                             FileInfo fileInfo = new FileInfo(destFullName);
                             fileInfo.CopyTo(targetPath);
                         }
                     }
                 }

            }


        }

        /// <summary>   
        /// 删除备份文件夹下的所有文件   
        /// </summary>   
        /// <param name="dirRoot">目录地址</param>   
        public static void DeleteBackupAllFile(string dirRoot)
        {
            if (!string.IsNullOrEmpty(dirRoot))
            {
                dirRoot = dirRoot + "\\";
                DirectoryInfo aDirectoryInfo = new DirectoryInfo(Path.GetDirectoryName(dirRoot));
                FileInfo[] files = aDirectoryInfo.GetFiles("*.*", SearchOption.AllDirectories);
                foreach (FileInfo f in files)
                {
                    f.IsReadOnly = false;
                    File.Delete(f.FullName);
                }
            }
        }   


      

        /// <summary>
        /// 解压下载需要更新的压缩包
        /// </summary>
        /// <param name="DestPatchFileSavePath">下载压缩包的路径</param>

        private void DecompressionPatchFile(string destPatchFileSavePath, string _PatchFileSaveFolderName, string targetVersion)
        {
            if (!string.IsNullOrEmpty(destPatchFileSavePath) && !string.IsNullOrEmpty(_PatchFileSaveFolderName))
            {
                OnUpdating(8, 2, "正在解压更新包...");
                //解压操作
                if (ZipUtil.UnZip
                    (destPatchFileSavePath, string.Empty, _PatchFileSaveFolderName))
                {
                    //读取已下载的xml文件信息

                    string xmlFilePath = "";
                    xmlFilePath = destPatchFileSavePath.Replace(System.IO.Path.GetFileName(destPatchFileSavePath), "") + _PatchFileSaveFolderName + "\\" + _PatchFileSaveFolderName + ".xml";
                    if (System.IO.File.Exists(xmlFilePath))
                    {
                        XmlDocument xmlUpdateFile = new XmlDocument();
                        xmlUpdateFile.Load(xmlFilePath);

                        XmlNode updateFileNodes = xmlUpdateFile.SelectSingleNode("Patch");
                        _updateFileNodes = null;

                        if (updateFileNodes != null)
                        {
                            //执行备份
                            OnUpdating(8, 3, "正在执行备份...");
                            BackupFiles(updateFileNodes);
                            _updateFileNodes = updateFileNodes;


                            string fileName = string.Empty; ;
                            string targetPath = string.Empty;
                            string filePath = string.Empty;
                            int index = 0;
                            int count = 0;
                            try
                            {
                                OnUpdating(8,4,"正在执行更新...");
                                _isUpdateFinished = false;
                                for (int i = 0; i < updateFileNodes.ChildNodes.Count; i++)
                                {
                                    count = updateFileNodes.ChildNodes.Count;
                                    index = i;
                                    XmlNode c = updateFileNodes.ChildNodes[i];
                                    if (c.Attributes != null)
                                    {
                                        fileName = c.Attributes["Name"].Value;
                                        targetPath = PathMap.GetTargetFilePath(_appInfo, c.Attributes["TargetPath"].Value);
                                        filePath = PathMap.GetFilePath(_appInfo, c.Attributes["Path"].Value, _PatchFileSaveFolderName);
                                        string oFilePath = c.Attributes["Path"].Value;
                                        if (System.IO.File.Exists(filePath))
                                        {
                                            if (File.Exists(targetPath))
                                            {
                                                File.Delete(targetPath);
                                            }
                                            else
                                            {
                                                //递归创建文件夹
                                                char[] sepatator = { '\\' };

                                                string[] filePaths = oFilePath.Split(sepatator, StringSplitOptions.RemoveEmptyEntries);
                                                CreateParentFolders(_appInfo.Directory, filePaths);
                                            }
                                            FileInfo fileInfo = new FileInfo(filePath);

                                          
                                            // CopyFilesUpdating(updateFileNodes.ChildNodes.Count, i, string.Format("复制文件 : {0}", fileName));
                                            fileInfo.CopyTo(targetPath);
                                        }
                                    }
                                }
                                _isUpdateFinished = true;
                              
                            }
                            catch (Exception ex)
                            {
                                Common.Logger.ErrorToTag("UpdatingProcess", "复制文件：{0}失败,targetPath:{1},ex:{2}",
                                fileName,
                                targetPath,
                                ex);
                                _failureFileName = fileName;
                                OnUpdatingFailure(8, 4, string.Format("复制文件：{0}失败",fileName ));
                                _isUpdateFinished = false;
                                return;
                            }
                            finally
                            {
                                OnUpdating(8, 7, "正在删除备份...");
                                DeleteBackupAllFile(_backupDestFullName);
                                OnUpdatingFinished(8, 8, "更新完毕...", _isUpdateFinished); 
                            }
                        }

                    }

                }

            }
            else
            {

            }
        }
    }
}
